/*
 * Copyright 2015 MingxingWang

 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at

 *     http://www.apache.org/licenses/LICENSE-2.0

 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.audaque.graphdb

import java.io.{DataInputStream, DataOutputStream}

/**
 * Created by Ming on 2015/3/26.
 */
class Property(val schema: Schema) extends Serializable {

  val size = if (schema == null) 0 else schema.size
  val values: Array[Any] = new Array[Any](size)
  var nullMask: Long = 0


  def apply(index: Int): Any = values(index)

  def apply(fieldName: String): Any = {
    val index = schema.getFieldIndex(fieldName)
    if (index == -1)
      throw new Exception("field name is not defined: " + fieldName)
    else
      values(index)
  }

  def get(index: Int): Any = {
    if (index < 0 || index >= size) {
      println("Warning, index out of rand in set [0," + size + "]: " + index)
      null
    } else {
      values(index)
    }
  }

  /**
   * 将输入的字符串值转换成该字段对应的格式
   * @param fieldName 字段名称
   * @param value  字段值
   * @return 是否成功
   */
  def adjustValue(fieldName: String, value: String): Boolean = {
    val index = schema.getFieldIndex(fieldName)
    if (index == -1) {
      println("field name is not defined: " + fieldName)
      false
    } else {
      adjustValue(index, value)
    }
  }

  /**
   * 将输入的字符串值转换成该字段对应的格式
   * @param index 字段下标
   * @param value  字段值
   * @return 是否成功
   */
  def adjustValue(index: Int, value: String): Boolean = {
    if (index < 0 || index >= size) {
      println("Warning, index out of rand in set [0," + size + "]: " + index)
      return false
    }
    set(index, schema.getFieldType(index).string2SuitableValue(value))
  }

  def set(index: Int, value: Any): Boolean = {
    if (index < 0 || index >= size) {
      println("Warning, index out of rand in set [0," + size + "]: " + index)
      return false
    }
    if (!schema.getFieldType(index).containValue(value)) {
      println("value type mismatches the field type")
      return false
    }
    values(index) = value
    true
  }

  def set(fieldName: String, value: Any): Boolean = {
    val index = schema.getFieldIndex(fieldName)
    if (index == -1) {
      println("field name is not defined: " + fieldName)
      false
    } else {
      set(index, value)
    }
  }

  def save(out: DataOutputStream): Property = {
    for (i <- 0 until size) {
      if (values(i) == null) {
        out.writeBoolean(false)
      } else {
        out.writeBoolean(true)
        schema.getFieldType(i).writer.write(values(i), out)
      }
    }
    this
  }

  def load(in: DataInputStream): Property = {
    for (i <- 0 until size) {
      if (in.readBoolean()) {
        values(i) = schema.getFieldType(i).reader.read(in)
      } else {
        values(i) = null
      }
    }
    this
  }

  def debug() = {
    val names = schema.getFieldNames
    for (i <- 0 until names.length) {
      print(names(i) + ": " + apply(names(i)) + ", ")
    }
  }
}

object Property {

  def apply(schema: Schema, values: Array[Any] = null): Property = {
    val prop = new Property(schema)
    if (schema != null && values != null) {
      var len = schema.size
      if (len > values.length) len = values.length
      for (i <- 0 until len) {
        prop.set(i, values(i))
      }
    }
    prop
  }
}
